package org.inspiration.dudu.web.aspect;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.inspiration.dudu.common.constant.RedisConstant;
import org.inspiration.dudu.common.util.RedisUtil;
import org.inspiration.dudu.user.model.vo.UserVO;
import org.inspiration.dudu.user.util.UserContextUtil;
import org.springframework.stereotype.Component;

import org.aspectj.lang.annotation.AfterThrowing;
import java.util.Arrays;

@Aspect
@Component
@RequiredArgsConstructor
@Slf4j
public class LoggingAspect {

    private final RedisUtil redisUtil;


    // 定义切入点，匹配带有 @Loggable 注解的类中的所有方法以及直接带有 @Loggable 注解的方法
    @Pointcut("@within(org.inspiration.dudu.web.annotation.Loggable) || @annotation(org.inspiration.dudu.web.annotation.Loggable)")
    public void loggableMethods() {}

    // 前置通知：在目标方法执行前记录日志
    @Before("loggableMethods()")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argsString = Arrays.toString(args);

        // 获取用户信息
        String username = "";
        Long userId = null;
        try {
            UserVO userVO = UserContextUtil.getUserVO();
            if (userVO != null) {
                username = userVO.getUsername();
                userId = userVO.getId();
            }
        } catch (Exception e) {
            log.warn("获取用户信息时出现异常", e);
        }

        log.info("用户 [ID: {}, 用户名: {}] 调用的方法 {} 即将执行，传入的参数为：{}", userId, username, methodName, argsString);

        //更新用户最近活跃时间
        if(userId != null) {
            redisUtil.addZSet(RedisConstant.ONLINE_USER_KEY, userId, System.currentTimeMillis());
        }
    }

    // 返回通知：在目标方法正常返回后记录日志
    @AfterReturning(pointcut = "loggableMethods()", returning = "result")
    public void afterMethodReturning(JoinPoint joinPoint, Object result) {
        String methodName = joinPoint.getSignature().getName();

        // 获取用户信息
        String username = "";
        Long userId = null;
        try {
            UserVO userVO = UserContextUtil.getUserVO();
            if (userVO != null) {
                username = userVO.getUsername();
                userId = userVO.getId();
            }
        } catch (Exception e) {
            log.warn("获取用户信息时出现异常", e);
        }

        log.info("用户 [ID: {}, 用户名: {}] 调用的方法 {} 已成功执行，返回结果为：{}", userId, username, methodName, result);
    }

    // 异常通知：在目标方法抛出异常时记录日志
    @AfterThrowing(pointcut = "loggableMethods()", throwing = "ex")
    public void afterMethodThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();

        // 获取用户信息
        String username = "";
        Long userId = null;
        try {
            UserVO userVO = UserContextUtil.getUserVO();
            if (userVO != null) {
                username = userVO.getUsername();
                userId = userVO.getId();
            }
        } catch (Exception e) {
            log.warn("获取用户信息时出现异常", e);
        }

        log.error("用户 [ID: {}, 用户名: {}] 调用的方法 {} 在执行过程中抛出异常：{}", userId, username, methodName, ex.getMessage(), ex);
    }
}